/**
	*****************************************************************************
	* @file     cmem7_can.h
	*
	* @brief    CMEM7 CAN header file
	*
	*
	* @version  V1.0
	* @date     3. September 2013
	*
	* @note               
	*           
	*****************************************************************************
	* @attention
	*
	* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
	* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
	* TIME. AS A RESULT, CAPITAL-MICRO SHALL NOT BE HELD LIABLE FOR ANY DIRECT, 
	* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
	* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
	* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
	*
	* <h2><center>&copy; COPYRIGHT 2013 Capital-micro </center></h2>
	*****************************************************************************
	*/
	
#ifndef __CMEM7_CAN_H
#define __CMEM7_CAN_H

#ifdef __cplusplus
 extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "cmem7.h"
#include "cmem7_conf.h"
	 
#define IS_CAN_ALL_PERIPH(PERIPH) (((PERIPH) == CAN0) || \
                                   ((PERIPH) == CAN1))

																
#define CAN_FLT_STANDARD_SINGLE    0x00000000
#define CAN_FLT_STANDARD_DUAL      0x00000001
#define CAN_FLT_EXTENDED_SINGLE    0x00000002
#define CAN_FLT_EXTENDED_DUAL      0x00000003

#define IS_CAN_FLT_TYPE(FILTER)    (((FILTER) == CAN_FLT_STANDARD_SINGLE) || \
                                    ((FILTER) == CAN_FLT_STANDARD_DUAL) || \
																		((FILTER) == CAN_FLT_EXTENDED_SINGLE) || \
                                    ((FILTER) == CAN_FLT_EXTENDED_DUAL))	
																		
#define IS_CAN_FLT_SINGLE(FILTER)  (((FILTER) == CAN_FLT_STANDARD_SINGLE) || \
                                    ((FILTER) == CAN_FLT_EXTENDED_SINGLE))

#define IS_CAN_FLT_DUAL(FILTER)    (IS_CAN_FLT_TYPE(FILTER) && \
                                    !IS_CAN_FLT_SINGLE(FILTER))
																		

#define CAN_CDR_DIV_1_2            0x0
#define CAN_CDR_DIV_1_4            0x1
#define CAN_CDR_DIV_1_6            0x2
#define CAN_CDR_DIV_1_8            0x3
#define CAN_CDR_DIV_1_10           0x4
#define CAN_CDR_DIV_1_12           0x5
#define CAN_CDR_DIV_1_14           0x6
#define CAN_CDR_DIV_1_1            0x7

#define IS_CAN_CDR_DIV(DIV)        (((DIV) == CAN_CDR_DIV_1_2) || \
                                    ((DIV) == CAN_CDR_DIV_1_4) || \
																		((DIV) == CAN_CDR_DIV_1_6) || \
																		((DIV) == CAN_CDR_DIV_1_8) || \
																		((DIV) == CAN_CDR_DIV_1_10) || \
																		((DIV) == CAN_CDR_DIV_1_12) || \
																		((DIV) == CAN_CDR_DIV_1_14) || \
																		((DIV) == CAN_CDR_DIV_1_1))		

#define CAN_INT_RBNF               0x01
#define CAN_INT_TB_UNLOCK          0x02
#define CAN_INT_ERR                0x04
#define CAN_INT_DATA_OVERRUN       0x08
#define CAN_INT_WAKEUP             0x10
#define CAN_INT_ERR_PASSIVE        0x20
#define CAN_INT_ARBITRATION_LOST   0x40
#define CAN_INT_BUS_ERR            0x80
#define CAN_INT_All                0xFF

#define IS_CAN_INT(INT)            (((INT) & ~CAN_INT_All) == 0)
                                   

typedef struct {
	uint16_t  ID28_18;                          /*!< 11 bits                                      */
  BOOL      RTR;                              /*!< if remote frame                              */
	uint8_t   data1;                            /*!< data byte 1, if not 2nd CAN_FLT_STANDARD_DUAL*/
	uint8_t   data2;                            /*!< data byte 2, if CAN_FLT_STANDARD_SINGLE      */
} CAN_STANDARD_FILTER;

typedef struct {
	uint16_t  ID28_13;                          /*!< 16 bits                                      */
	uint16_t  ID12_0;                           /*!< 13 bits, if CAN_FLT_EXTENDED_SINGLE          */
  BOOL      RTR;                              /*!< if remote frame, if CAN_FLT_EXTENDED_SINGLE  */
} CAN_EXTENDED_FILTER;

typedef struct {
	uint8_t   type;                             /*!< ref as FILTER_TYPE                           */
	union {
		CAN_STANDARD_FILTER sf;
		CAN_EXTENDED_FILTER ef;
	} ACCEPT;
	
	union {
		CAN_STANDARD_FILTER sf;                   /*!< 1 means 'don't care'                          */
		CAN_EXTENDED_FILTER ef;
	} MASK;
} CAN_FILTER;

typedef struct {	
	BOOL CAN_TxEn;            /*!< if only receive data */
	
	BOOL CAN_Loopback;        /*!< if self-transmitted and self-received */
	
  uint8_t CAN_ClockDiv;     /*!< input clock divider, ref as CAN_CDR_DIV */                               

	uint16_t CAN_Prescaler;   /*!< Specifies the length of a time quantum. 
	                               Time quantum = (CAN_Prescaler + 1) * 2 * input clock */
  
  uint8_t CAN_SJW;          /*!< Specifies the maximum number of time quanta 
                                 the CAN hardware is allowed to lengthen or 
                                 shorten a bit to perform resynchronization.
                                 This parameter can be a value of 
                                 @ref CAN_synchronisation_jump_width */

	uint8_t CAN_TSEG1;        /*!< the maximum number of time quanta of propagation and 1st phase
                                 segment */
  uint8_t CAN_TSEG2;        /*!< the maximum number of time quanta of 2nd phase segment*/
	
  BOOL CAN_HighSpeed;       /*!< if high speed */
} CAN_InitTypeDef;


typedef struct
{
  BOOL SFF;        /*!< If standard frame format */
  
	uint32_t Id;     /*!< Specifies the identifier.
                        This parameter can be a value between 0 to 0x1FFFFFFF. */

  BOOL RTR;        /*!< Specifies the type of frame for the message that will 
                        be transmitted. This parameter can be a value of 
                        @ref CAN_remote_transmission_request */

  uint8_t DLC;     /*!< Specifies the length of the frame that will be 
                        transmitted. This parameter can be a value between 
                        0 to 8 */

  uint8_t Data[8]; /*!< Contains the data to be transmitted. It ranges from 0 
                        to 0xFF. */
} CAN_Frame;


BOOL CAN_Init(CAN0_Type* CANx, CAN_InitTypeDef* CAN_InitStruct, 
  CAN_FILTER *f1, CAN_FILTER *f2);

void CAN_SetSleepMode(CAN0_Type* CANx, BOOL enable);

void CAN_EnableInt(CAN0_Type* CANx, uint32_t Int, BOOL enable);
/* all interrupts except for receive int are cleared after call this func */
uint8_t CAN_GetIntStatus(CAN0_Type* CANx);

BOOL CAN_Transmit(CAN0_Type* CANx, CAN_Frame* frame);
BOOL CAN_Receive(CAN0_Type* CANx, CAN_Frame* frame);

#ifdef __cplusplus
}
#endif

#endif /* __CMEM7_CAN_H */
